//
//  YK_MyImage.m
//  VANCL
//
//  Created by yek on 10-11-18.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "YKImage.h"
#import "YKCache.h"

#pragma mark YKImageLoadOperation

@class YKImageLoadOperation;

@protocol YImageLoadOperationDelegate<NSObject>
/*
 图片加载完成
 */
-(void) imageLoadOperation:(YKImageLoadOperation*) imageLoadOperation loadedImage:(UIImage*) image url:(NSString*) url ;
@end

@interface YKImageLoadOperation : NSOperation
{
	NSString* url;
	id<YImageLoadOperationDelegate> delegate;
}
-(id) initWithImageUrl:(NSString*) aurl  delegate:(id<YImageLoadOperationDelegate>) adelegate;

@end

/*
 //TODO:添加缓存移除策略
 */
@implementation YKImageLoadOperation

const int CACHE_CAPACITY=50;
const BOOL CACHE_ENABLE=NO;
NSMutableDictionary* cache;
+(void) initialize{
	if(CACHE_ENABLE){
		assert(CACHE_CAPACITY>0);
		cache=[[NSMutableDictionary alloc] initWithCapacity:CACHE_CAPACITY];
	}
}

-(id) initWithImageUrl:(NSString*) aurl  delegate:(id<YImageLoadOperationDelegate>) adelegate{
	assert(aurl!=nil);
	if(self=[super init]){
		url=[aurl retain];
		delegate=[adelegate retain];
	}
	return self;
}

-(void) dealloc{
	[url release];
	[delegate release];
	[super dealloc];
}
-(void) performDelegateMethod:(id) sender{
	UIImage* image=(UIImage*) sender;
	[delegate imageLoadOperation:self loadedImage:image url:url ];
	[image release];
}
-(void) main{
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	UIImage* image=nil;
	if(CACHE_ENABLE){
		image=(UIImage*)[cache objectForKey:url];
	}
	if(image==nil){
		image=[YKImage imageFromUrl:url];
		if(image!=nil && CACHE_ENABLE){
			@synchronized(cache){
				if([cache count]>CACHE_CAPACITY){
					[cache removeObjectForKey:[[cache allKeys] objectAtIndex:0]];
				}
				[cache setObject:image forKey:url];
			}
		}
	}
	if(delegate!=nil){
		//[delegate imageLoadOperation:self loadedImage:image url:url ];
		[self performSelectorOnMainThread:@selector(performDelegateMethod:) withObject:[image retain] waitUntilDone:NO];
	}
	[pool release];
}

@end

#pragma mark YKImageLoadOperationHandler
@interface YKImageLoadOperationHandler : NSObject<YImageLoadOperationDelegate>
{
	id object;
	SEL action;
	id param;
}
/*
 action:
	(void) *****:(UIImage*) image url:(NSString*) url;
 */
-(id) initWithObject:(id) aobject action:(SEL)aaction param:(id) aparam;
@end

@implementation YKImageLoadOperationHandler
NSTimeInterval startTime;
-(id) initWithObject:(id)aobject action:(SEL)aaction param:(id) aparam{
	if(self=[super init]){
		startTime=[[NSDate date] timeIntervalSince1970];
		object=[aobject retain];
		action=aaction;
		param=[aparam retain];
	}
	return self;
}

-(void) imageLoadOperation:(YKImageLoadOperation *)imageLoadOperation loadedImage:(UIImage *)image url:(NSString *)url{
	[object performSelector:action withObject:image withObject:param];
	//NSTimeInterval endTime=[[NSDate date] timeIntervalSince1970];
	////!! NSLog(@"%@ timespan %f startTime:%f endTime:%f",[self class],endTime-startTime,startTime, endTime);
}

-(void) dealloc{
	[param release];
	[object release];
	[super dealloc];
}


@end

#pragma mark YKImageLoadOperationHandlerSetImage
@interface YKImageLoadOperationHandlerSetImage : NSObject
{
	UIImageView* imageView;
	UIActivityIndicatorView* indicatorView;
}
-(id) initWithImageView:(UIImageView*) aimageView;
-(void) onLoadedImage:(UIImage*) image url:(NSString*) url;

@end

@implementation YKImageLoadOperationHandlerSetImage

-(void) showIndicator:(id) obj{
	indicatorView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
	indicatorView.frame=CGRectMake(imageView.bounds.origin.x+(imageView.bounds.size.width-20)/2.0, imageView.bounds.origin.y+(imageView.bounds.size.height-20)/2.0, 20, 20);
	[imageView addSubview:indicatorView];
	[indicatorView startAnimating];
	[indicatorView release];
}
-(void) hideIndicator:(id) obj{
	[indicatorView stopAnimating];
	[indicatorView removeFromSuperview];
	indicatorView=nil;
}

-(id) initWithImageView:(UIImageView *)aimageView{
	if(self=[super init]){
		imageView=[aimageView retain];
		[self performSelectorOnMainThread:@selector(showIndicator:) withObject:nil waitUntilDone:NO];
	}
	return self;
}

-(void) onLoadedImage:(UIImage *)image url:(NSString *)url{
	[self performSelectorOnMainThread:@selector(hideIndicator:) withObject:nil waitUntilDone:NO];
	[imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}

-(void) dealloc{
	[self hideIndicator:nil];
	[imageView release];
	[super dealloc];
}

@end






@implementation YKImage

static YKFileCache* fileCache;
+(UIImage*) imageFromUrl:(NSString *)url{
	UIImage* ret=[YKImage imageFromUrl:url cacheEnable:YES];
	return ret;
}
+(UIImage*) imageFromUrl_nil:(NSString *)url  cacheEnable:(BOOL) cacheEnable{
	return nil;
}
+(NSData*) dataFromUrl:(NSString *)url timeoutInterval:(NSTimeInterval) timeoutInterval{
	static int count=0;
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	++count;
	
	NSURLRequest* request=[NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:timeoutInterval];
	NSError* error;
	NSURLResponse* response;
	NSData* ret=[[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] retain];
	[pool release];
	--count;
	//!! NSLog(@"dataFromUrl count=%d",count);
	return [ret autorelease];	
}
+(UIImage*) imageFromUrl:(NSString *)url timeoutInterval:(NSTimeInterval) timeoutInterval{
	static int count=0;
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	++count;
	NSData* data=[YKImage dataFromUrl:url timeoutInterval:timeoutInterval];
	UIImage* ret=nil;
	if(data!=nil){
		ret=[[UIImage imageWithData:data] retain];
	}
	[pool release];
	--count;
	//!! NSLog(@"imageFromUrl count=%d",count);
	return [ret autorelease];	
}

+(UIImage*) imageFromUrl__:(NSString *)url  cacheEnable:(BOOL) cacheEnable{
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	//NSData* data=[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
	NSError* error;
	NSData* data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url] options:NSUncachedRead error:&error];
	UIImage* ret=[[UIImage imageWithData:data] retain];
	[pool release];
	return [ret autorelease];
}
+(UIImage*) imageFromUrl_conn:(NSString *)url  cacheEnable:(BOOL) cacheEnable{
	return [YKImage imageFromUrl:url timeoutInterval:10];
}
+(UIImage*) imageFromUrl:(NSString *)url  cacheEnable:(BOOL) cacheEnable{
	////!! NSLog(@"+(UIImage*) imageFromUrl:(NSString *)url=%@ enter...",url);
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	UIImage* ret=nil;
	NSData* dataCache=nil;
	if(cacheEnable){
		dataCache=[fileCache objectForKey:url];
		if(nil!=dataCache){
			ret=[[UIImage imageWithData:dataCache] retain];
		}
	}
	if(nil==ret){
		//load from url
		NSURL *tUrl = [[NSURL alloc] initWithString:url];
		//没法设置超时时间
		NSError* error=nil;
		NSData* data = [[NSData alloc] initWithContentsOfURL:tUrl options:0 error:&error];
		[tUrl release];
		//data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
		//NSData* data=[YK_MyImage dataFromUrl:url timeoutInterval:10];
		if(data!=nil && error==nil){
			ret=[[UIImage imageWithData:data] retain];
			////!! NSLog(@"ret.size(%f,%f)",ret.size.width,ret.size.height);
		}
		//[pool release];
		
		if(ret==nil){
			//!! NSLog(@"warning! +(UIImage*) imageFromUrl:(NSString *)url=%@ return nil", url);
		}else{
			if(cacheEnable){
				[fileCache setObject:data forKey:url expireDate:[[NSDate date] dateByAddingTimeInterval:60*60*24*7 ] ];
			}
		}
		[data release];
	}
	[pool release];
	return [ret autorelease];
}

//static NSMutableArray* queueOperation;
static NSOperationQueue* queue;
+(void) initialize{
	//queueOperation=[[NSMutableArray alloc] init];
	queue=[[NSOperationQueue alloc] init];
	fileCache=[[YKFileCache  alloc] initWithFileName:@"imageFileCache2.dat"];
}

+(void) queueLoadImageFromUrl:(NSString *)url imageView:(UIImageView *)imageView{
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	YKImageLoadOperationHandlerSetImage* setImageHandler=[[YKImageLoadOperationHandlerSetImage alloc] initWithImageView:imageView];
	imageView.image=nil;
	[YKImage queueLoadImageFromUrl:url object:setImageHandler action:@selector(onLoadedImage:url:) param:nil];
	[setImageHandler release];
	[pool release];
}

+(void) queueLoadImageFromUrl:(NSString *)url object:(id) object action:(SEL) action  param:(id)param{
	NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
	YKImageLoadOperationHandler* handler=[[YKImageLoadOperationHandler alloc] initWithObject:object action:action param:param];
	YKImageLoadOperation* operation=[[YKImageLoadOperation alloc] initWithImageUrl:url delegate:handler];
	[queue performSelectorInBackground:@selector(addOperation:) withObject:operation];
	//[queueOperation addObject:queueOperation];
	//[queue addOperation:operation];
	[operation release];
	[handler release];
	[pool release];
}

@end



#pragma mark  category uibutton

@implementation UIButton( setImageFromUrl )

-(void) setImageFromUrl:(NSString*) urlString  forState:(UIControlState)state{
	if(urlString==nil){
		//!! NSLog(@"!!!!warning urlString is nil");
		return;
	}
	[YKImage queueLoadImageFromUrl:urlString object:self action:@selector(setImage:param:) param:nil];
}
-(void) setImage:(UIImage*) image param:(id) param{
	[self setImage:image forState:UIControlStateNormal];
}


@end



#pragma mark UIImage
@implementation UIImageView (setImageFromUrl )


-(void) setImageFromUrl:(NSString*) urlString{
	if(urlString==nil){
		//!! NSLog(@"!!!!warning urlString is nil");
		return;
	}
	[YKImage queueLoadImageFromUrl:urlString imageView:self];
}


@end






